﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Runtime.InteropServices;
using System.Text;
using log4net;

namespace Close.io.Client
{
	public class CloseIoClient 
	{
		private readonly string _apiKey;
		private readonly string _timeZoneOffset;
		private readonly string _baseUrl;
		private static readonly ILog log = LogManager.GetLogger("CloseIoClient");

		public CloseIoClient()
		{
			_baseUrl = ConfigurationManager.AppSettings["BaseUrl"];
			_apiKey = ConfigurationManager.AppSettings["ApiKey"];
			_timeZoneOffset = ConfigurationManager.AppSettings["X-TZ-OFFSET"];		
		}

		public CloseIoClient(string baseUrl, string apiKey, string timeZoneOffset)
		{
			_baseUrl = baseUrl;
			_apiKey = apiKey;
			_timeZoneOffset = timeZoneOffset;
		}

		

		public CloseIoApiResult Get(string endPoint,Dictionary<string, string> queryParameters)
		{

			var buffer = new StringBuilder();

			foreach (var queryParameter in queryParameters)
			{
				if (buffer.Length == 0)
					buffer.AppendFormat("{0}={1}", queryParameter.Key, queryParameter.Value);
				else
				{
					buffer.AppendFormat("&{0}={1}", queryParameter.Key, queryParameter.Value);
				}
			}
			buffer.Insert(0, "?");
			string queryString = buffer.ToString();
			CloseIoApiResult closeIoApiResult = null; 
			using (var httpClient = new HttpClient())
			{
				SetDefaults(httpClient);


				var relativeUrl = string.Format("{0}/", endPoint, queryString);
				

				HttpResponseMessage response = httpClient.GetAsync(relativeUrl).Result;
				var content = response.Content.ReadAsStringAsync().Result;
				closeIoApiResult = new CloseIoApiResult() { Content = content, StatusCode = response.StatusCode, ReasonPhrase = response.ReasonPhrase };
				log.InfoFormat(Properties.Resources.LogGetMessage, endPoint, response.StatusCode);

			}
			return closeIoApiResult;
		}

		public CloseIoApiResult Get(string endPoint)
		{
			string result = string.Empty;
			CloseIoApiResult closeIoApiResult = null;
			using (var httpClient = new HttpClient())
			{
				SetDefaults(httpClient);

				string relativeUrl = string.Empty;
			 
					relativeUrl = string.Format("{0}/", endPoint);

				HttpResponseMessage response = httpClient.GetAsync(relativeUrl).Result;
				var content = response.Content.ReadAsStringAsync().Result;
				closeIoApiResult = new CloseIoApiResult() { Content = content, StatusCode = response.StatusCode, ReasonPhrase = response.ReasonPhrase };
				log.InfoFormat(Properties.Resources.LogGetMessage, endPoint, response.StatusCode);

			}
			return closeIoApiResult;
		}

		public CloseIoApiResult Get(string endPoint, string id)
		{
			string result = string.Empty;
			CloseIoApiResult closeIoApiResult = null;
			using (var httpClient = new HttpClient())
			{
				SetDefaults(httpClient);

				string relativeUrl = string.Empty;
				if (!string.IsNullOrEmpty(id))
					relativeUrl = string.Format("{0}/{1}/", endPoint, id);
				else
					relativeUrl = string.Format("{0}/", endPoint);

				HttpResponseMessage response = httpClient.GetAsync(relativeUrl).Result;
				var content = response.Content.ReadAsStringAsync().Result;
				closeIoApiResult = new CloseIoApiResult() { Content = content, StatusCode = response.StatusCode, ReasonPhrase = response.ReasonPhrase };
				log.InfoFormat(Properties.Resources.LogGetMessage, endPoint, response.StatusCode);

			}
			return closeIoApiResult;
		}

		public CloseIoApiResult Get(string endPoint, string id, string queryString)
		{
			string result = string.Empty;
			CloseIoApiResult closeIoApiResult = null; 
			using (var httpClient = new HttpClient())
			{
				SetDefaults(httpClient);

				string relativeUrl = string.Empty;
				if (!string.IsNullOrEmpty(id))
				{
					if (!queryString.StartsWith("?"))
						queryString = "?" + queryString;
					relativeUrl = string.Format("{0}/{1}/{2}", endPoint, id, queryString);
				}
				else
					relativeUrl = string.Format("{0}/{1}", endPoint, queryString);


				HttpResponseMessage response = httpClient.GetAsync(relativeUrl).Result;
				var content = response.Content.ReadAsStringAsync().Result;
				closeIoApiResult = new CloseIoApiResult(){Content = content,StatusCode = response.StatusCode,ReasonPhrase = response.ReasonPhrase};
				log.InfoFormat(Properties.Resources.LogGetMessage, endPoint, response.StatusCode);
				
			}
			return closeIoApiResult;
		}

		private void SetDefaults(HttpClient httpClient)
		{
			httpClient.MaxResponseContentBufferSize = int.MaxValue;
			httpClient.BaseAddress = new Uri(_baseUrl);

			string encoded = Convert.ToBase64String(Encoding.UTF8.GetBytes(_apiKey + ":"));
			httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
			httpClient.DefaultRequestHeaders.Add("Authorization", "Basic " + encoded);
			if (!string.IsNullOrEmpty(_timeZoneOffset))
			{
				httpClient.DefaultRequestHeaders.Add("X-TZ-OFFSET", _timeZoneOffset);
			}
			
		}

		public CloseIoApiResult Post(string endPoint, string data)
		{
			return Post(endPoint, string.Empty, data);
		}

		public CloseIoApiResult Post(string endPoint, string id, string data)
		{
			if (!endPoint.EndsWith("/"))
				endPoint = endPoint + "/";

			if (!id.EndsWith("/"))
				id = id + "/";
			string relativeUrl;
			if (string.IsNullOrEmpty(id))
				relativeUrl = endPoint + id;
			else
				relativeUrl = endPoint;

			string result = string.Empty;
			var httpClientHandler = new HttpClientHandler {AllowAutoRedirect = false};
			CloseIoApiResult closeIoApiResult = null; 
			using (var httpClient = new HttpClient(httpClientHandler))
			{
				httpClient.MaxResponseContentBufferSize = int.MaxValue;
				httpClient.BaseAddress = new Uri(_baseUrl);
				string encoded = Convert.ToBase64String(Encoding.UTF8.GetBytes(_apiKey + ":"));
				httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
				httpClient.DefaultRequestHeaders.Add("Authorization", "Basic " + encoded);
				var requestMessage = new HttpRequestMessage(HttpMethod.Post, relativeUrl)
				{
					Content = new StringContent(data)
				};

				requestMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");

				HttpResponseMessage response = httpClient.SendAsync(requestMessage).Result;

				var content = response.Content.ReadAsStringAsync().Result;
				closeIoApiResult = new CloseIoApiResult(){Content = content,StatusCode = response.StatusCode,ReasonPhrase = response.ReasonPhrase};
				log.InfoFormat(Properties.Resources.LogPostMessage, endPoint, response.StatusCode);
			}
			return closeIoApiResult;
		}


		public CloseIoApiResult Put(string endPoint, string id, string data)
		{
			string result = string.Empty;
			CloseIoApiResult closeIoApiResult = null; 
			using (var httpClient = new HttpClient())
			{
				httpClient.MaxResponseContentBufferSize = int.MaxValue;
				httpClient.BaseAddress = new Uri(_baseUrl);

				if (!endPoint.EndsWith("/"))
					endPoint = endPoint + "/";

				if (!id.EndsWith("/"))
					id = id + "/";

				var requestMessage = new HttpRequestMessage(HttpMethod.Put, endPoint + id)
				{
					Content = new StringContent(data)
				};

				string encoded = Convert.ToBase64String(Encoding.UTF8.GetBytes(_apiKey + ":"));
				requestMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
				requestMessage.Headers.Add("Authorization", "Basic " + encoded);
				requestMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
				HttpResponseMessage response = httpClient.SendAsync(requestMessage).Result;

				var content = response.Content.ReadAsStringAsync().Result;
				closeIoApiResult = new CloseIoApiResult(){Content = content,StatusCode = response.StatusCode,ReasonPhrase = response.ReasonPhrase};
				log.InfoFormat(Properties.Resources.LogPutMessage, endPoint + id, data, response.StatusCode);
				
			}
			return closeIoApiResult;
		}

		public CloseIoApiResult Delete(string endPoint, string id)
		{
			CloseIoApiResult closeIoApiResult = null; 
			using (var httpClient = new HttpClient())
			{
				SetDefaults(httpClient);

				string relativeUrl = string.Empty;
				if (!string.IsNullOrEmpty(id))
					relativeUrl = string.Format("{0}/{1}/", endPoint, id);
				else
					relativeUrl = string.Format("{0}/", endPoint);

				HttpResponseMessage response = httpClient.DeleteAsync(relativeUrl).Result;
				var content = response.Content.ReadAsStringAsync().Result;				
				closeIoApiResult = new CloseIoApiResult(){Content = content,StatusCode = response.StatusCode,ReasonPhrase = response.ReasonPhrase};
				log.InfoFormat(Properties.Resources.LogDeleteMessage, endPoint, response.StatusCode);
			}

			return closeIoApiResult;
		}
	}


	
}